#pragma ident "$ID: CommonModels.hpp 2015-11-06 $"


#ifndef COMMON_MODLES_HPP
#define COMMON_MODELS_HPP

//============================================================================
//  Function
//
//  ALL common model corrections for GNSS data are encapsulated here.
//
//  Copyright (c)
//
//  2019.4.25, S.J.Zhang
//
//============================================================================

#include "ProcessingClass.hpp"
#include "DataStructures.hpp"
#include "CommonHeader.hpp"

#include "DCBDataReader.hpp"
#include "MGEXDCBCorrection.hpp"
#include "SimpleFilter.hpp"
#include "RequireObservables.hpp"
#include "ConvertObservables.hpp"
#include "LinearCombinations.hpp"
#include "ComputeLinear.hpp"
#include "MWCSDetector.hpp"
#include "LICSDetector.hpp"
#include "SatArcMarker.hpp"
#include "CSDetectorLC.hpp"

#include "MWSmoother.hpp"
#include "BasicModel.hpp"
#include "ComputeElevWeights.hpp"
#include "ComputeTropModel.hpp"
#include "ComputeStaTides.hpp"
#include "CorrectObservables.hpp"
#include "GravitationalDelay.hpp"
#include "ComputeSatAttitude.hpp"
#include "ComputeSatPCenter.hpp"
#include "ComputeWindUp.hpp"
#include "PhaseCodeAlignment.hpp"
#include "ComputeStaClock.hpp"
#include "EclipsedSatFilter.hpp"
#include "XYZ2NEU.hpp"
#include "IFCBCorrection.hpp"

namespace gpstk
{

   //
   /**  
    * A typical way to use this class follows:
    *
    * @code
    *
    * globalGnssData ggd;
    *
    * CommonModels commonModels;
    * 
    * CommonTime iterTime(beginTime);
    * while(iterTime< endTime)
    * {
    *    network.readEpochData(iterTime,ggd);
    *    ggd >> commonModels ;
    * }
    *
    * @endcode
    *
    * @sa
    *
    */
    class CommonModels : public ProcessingClass
    {
    public :

        // Default constructr
        CommonModels() 
            : csMethod(1)
        {
            defaultSettings();
        };


        /** Return a gnssRinex object, adding the new data generated
         *  when calling this object.
         *
         * @param gData     Data object holding the data.
         */
        virtual void Process(commonHeader& comHeader, gnssRinex& gData)
            noexcept(false);


        /** Return a sourceRinex object, adding the new data generated
         *  when calling this object.
         *
         * @param gData     Data object holding the data.
         */
        virtual void Process(commonHeader& comHeader, sourceRinex& gData);


        virtual void setKinematic(bool kinematic)
        {
            basicModel.setKinematic(kinematic);
        };

        virtual void setCSMethod(int method)
        {
            csMethod = method;
        };

        virtual void setMinElev(double minElev)
        {
            basicModel.setMinElev(minElev);
        };

        virtual void setCorrectIFCB(bool correct)
        {
            correctIFCB = correct;
        };

        virtual void setLCDetector(CSDetectorLC& detector)
        {
            pLCDetector = &detector;
        };

        void defaultSettings()
        {
            simFilter.setFilteredType(TypeID::C1W);
            simFilter.addFilteredType(TypeID::C2W);
            simFilter.addFilteredType(TypeID::C5X);

            simFilter.addGLOFilteredType(TypeID::C1P);
            simFilter.addGLOFilteredType(TypeID::C2P);
            simFilter.addGALFilteredType(TypeID::C1X);
            simFilter.addGALFilteredType(TypeID::C5X);
            simFilter.addGALFilteredType(TypeID::C7X);
            simFilter.addGALFilteredType(TypeID::C8X);

            simFilter.addBDSFilteredType(TypeID::C2I);
            simFilter.addBDSFilteredType(TypeID::C6I);
            simFilter.addBDSFilteredType(TypeID::C7I);

            requireObs.addRequiredType(TypeID::C1);
            requireObs.addRequiredType(TypeID::C2);
            requireObs.addRequiredType(TypeID::L1);
            requireObs.addRequiredType(TypeID::L2);

            requireObs.addRequiredType(TypeID::C1, SatelliteSystem::Galileo);
            requireObs.addRequiredType(TypeID::C5, SatelliteSystem::Galileo);
            requireObs.addRequiredType(TypeID::L1, SatelliteSystem::Galileo);
            requireObs.addRequiredType(TypeID::L5, SatelliteSystem::Galileo);

            // only BDS-2
            requireObs.addRequiredType(TypeID::C2, SatelliteSystem::BDS);
            requireObs.addRequiredType(TypeID::C7, SatelliteSystem::BDS);
            requireObs.addRequiredType(TypeID::L2, SatelliteSystem::BDS);
            requireObs.addRequiredType(TypeID::L7, SatelliteSystem::BDS);

            // GPS mw/li/pc/lc
            combs1.addLinear(linearComb.mw12CombOfGPS);
            combs1.addLinear(linearComb.mw15CombOfGPS);
            combs1.addLinear(linearComb.mw25CombOfGPS);

            combs1.addLinear(linearComb.li12CombOfGPS);

            combs1.addLinear(linearComb.pc12CombOfGPS);
            combs1.addLinear(linearComb.pc15CombOfGPS);

            combs1.addLinear(linearComb.lc12CombOfGPS);
            combs1.addLinear(linearComb.lc15CombOfGPS);

            // GAL mw/li/pc/lc
            combs1.addLinear(linearComb.mw15CombOfGAL, SatelliteSystem::Galileo);

            combs1.addLinear(linearComb.li15CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.li17CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.li18CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.li16CombOfGAL, SatelliteSystem::Galileo);

            combs1.addLinear(linearComb.pc15CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.pc17CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.pc18CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.pc16CombOfGAL, SatelliteSystem::Galileo);

            combs1.addLinear(linearComb.lc15CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.lc17CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.lc18CombOfGAL, SatelliteSystem::Galileo);
            combs1.addLinear(linearComb.lc16CombOfGAL, SatelliteSystem::Galileo);

            // BDS mw/li/pc/lc
            combs1.addLinear(linearComb.mw27CombOfBDS, SatelliteSystem::BDS);

            combs1.addLinear(linearComb.li27CombOfBDS, SatelliteSystem::BDS);
            combs1.addLinear(linearComb.li26CombOfBDS, SatelliteSystem::BDS);

            combs1.addLinear(linearComb.pc27CombOfBDS, SatelliteSystem::BDS);
            combs1.addLinear(linearComb.pc26CombOfBDS, SatelliteSystem::BDS);
            combs1.addLinear(linearComb.lc27CombOfBDS, SatelliteSystem::BDS);
            combs1.addLinear(linearComb.lc26CombOfBDS, SatelliteSystem::BDS);

            basicModel.setDefaultObs(TypeID::PC12, SatelliteSystem::GPS);
            basicModel.setDefaultObs(TypeID::PC15, SatelliteSystem::Galileo);
            basicModel.setDefaultObs(TypeID::PC27, SatelliteSystem::BDS);

            satPCenter.setEclipse(eclipsedSV);

              // MWCSDetector
            markCSMW12GPS.setObsType(TypeID::MW12);
            markCSMW12GPS.setMaxNumCycles(0.9);
            markCSMW12GPS.setDeltaTMax( 61.0 );
            markCSMW12GPS.setUseLLI(true);

              // MWCSDetector
            markCSMW15GPS.setObsType(TypeID::MW15);
            markCSMW15GPS.setMaxNumCycles(0.9);
            markCSMW15GPS.setDeltaTMax( 61.0 );
            markCSMW15GPS.setUseLLI(true);

              // LICSDetector
            markCSLI12GPS.setObsType(TypeID::LI12);
            markCSLI12GPS.setDeltaTMax( 61.0 );
            markCSLI12GPS.setMinThreshold(0.240);
            markCSLI12GPS.setLIDrift(0.002);
            markCSLI12GPS.setUseLLI(true);

            markCSLI15GPS.setObsType(TypeID::LI15);
            markCSLI15GPS.setDeltaTMax( 61.0 );
            markCSLI15GPS.setMinThreshold(0.240);
            markCSLI15GPS.setLIDrift(0.002);
            markCSLI15GPS.setUseLLI(true);

              // GAL MWCSDetector
            markCSMW15GAL.setObsType(TypeID::MW15, SatelliteSystem::Galileo);
            markCSMW15GAL.setMaxNumCycles(0.9);
            markCSMW15GAL.setDeltaTMax( 61.0 );
            markCSMW15GAL.setUseLLI(true);

              // LICSDetector
            markCSLI15GAL.setObsType(TypeID::LI15, SatelliteSystem::Galileo);
            markCSLI15GAL.setDeltaTMax( 61.0 );
            markCSLI15GAL.setMinThreshold(0.240);
            markCSLI15GAL.setLIDrift(0.002);
            markCSLI15GAL.setUseLLI(true);

              // LICSDetector
            markCSLI17GAL.setObsType(TypeID::LI17, SatelliteSystem::Galileo);
            markCSLI17GAL.setDeltaTMax( 61.0 );
            markCSLI17GAL.setMinThreshold(0.240);
            markCSLI17GAL.setLIDrift(0.002);
            markCSLI17GAL.setUseLLI(true);

              // LICSDetector
            markCSLI18GAL.setObsType(TypeID::LI18, SatelliteSystem::Galileo);
            markCSLI18GAL.setDeltaTMax( 61.0 );
            markCSLI18GAL.setMinThreshold(0.240);
            markCSLI18GAL.setLIDrift(0.002);
            markCSLI18GAL.setUseLLI(true);

            markCSLI16GAL.setObsType(TypeID::LI16, SatelliteSystem::Galileo);
            markCSLI16GAL.setDeltaTMax( 61.0 );
            markCSLI16GAL.setMinThreshold(0.240);
            markCSLI16GAL.setLIDrift(0.002);
            markCSLI16GAL.setUseLLI(true);

              // BDS MWCSDetector
            markCSMW27BDS.setObsType(TypeID::MW27, SatelliteSystem::BDS);
            markCSMW27BDS.setMaxNumCycles(0.9);
            markCSMW27BDS.setDeltaTMax( 61.0 );
            markCSMW27BDS.setUseLLI(true);

              // LICSDetector
            markCSLI27BDS.setObsType(TypeID::LI27, SatelliteSystem::BDS);
            markCSLI27BDS.setDeltaTMax( 61.0 );
            markCSLI27BDS.setMinThreshold(0.240);
            markCSLI27BDS.setLIDrift(0.002);
            markCSLI27BDS.setUseLLI(true);

            markCSLI26BDS.setObsType(TypeID::LI26, SatelliteSystem::BDS);
            markCSLI26BDS.setDeltaTMax( 61.0 );
            markCSLI26BDS.setMinThreshold(0.240);
            markCSLI26BDS.setLIDrift(0.002);
            markCSLI26BDS.setUseLLI(true);

            prefitIFCS.addLinear(linearComb.c1PrefitOfGPS);
            prefitIFCS.addLinear(linearComb.c2PrefitOfGPS);
            prefitIFCS.addLinear(linearComb.l1PrefitOfGPS);
            prefitIFCS.addLinear(linearComb.l2PrefitOfGPS);
            prefitIFCS.addLinear(linearComb.pc12PrefitOfGPS);
            prefitIFCS.addLinear(linearComb.lc12PrefitOfGPS);
            prefitIFCS.addLinear(linearComb.wl12PrefitOfGPS);
            prefitIFCS.addOptionalType(TypeID::updL1);
            prefitIFCS.addOptionalType(TypeID::updL2);
            prefitIFCS.addOptionalType(TypeID::windUp);

            windUp.setEclipse(eclipsedSV);

            phaseAlignGPSL1.setSatSystem(SatelliteSystem::GPS);
            phaseAlignGPSL1.setCodeType(TypeID::C1);
            phaseAlignGPSL1.setPhaseType(TypeID::L1);
            phaseAlignGPSL1.setPhaseWavelength(L1_WAVELENGTH_GPS);
            phaseAlignGPSL1.setUseSatArc(true);

            phaseAlignGPSL2.setSatSystem(SatelliteSystem::GPS);
            phaseAlignGPSL2.setCodeType(TypeID::C2);
            phaseAlignGPSL2.setPhaseType(TypeID::L2);
            phaseAlignGPSL2.setPhaseWavelength(L2_WAVELENGTH_GPS);
            phaseAlignGPSL2.setUseSatArc(true);

            phaseAlignGPSL5.setSatSystem(SatelliteSystem::GPS);
            phaseAlignGPSL5.setCodeType(TypeID::C5);
            phaseAlignGPSL5.setPhaseType(TypeID::L5);
            phaseAlignGPSL5.setPhaseWavelength(L5_WAVELENGTH_GPS);
            phaseAlignGPSL5.setUseSatArc(true);

            // GPS
            combs2.addLinear(linearComb.pc12CombOfGPS);
            combs2.addLinear(linearComb.pc15CombOfGPS);
            combs2.addLinear(linearComb.lc12CombOfGPS);
            combs2.addLinear(linearComb.lc15CombOfGPS);
            combs2.addLinear(linearComb.mw12CombOfGPS);
            combs2.addLinear(linearComb.mw15CombOfGPS);


            // GAL
            combs2.addLinear(linearComb.pc15CombOfGAL, SatelliteSystem::Galileo);
            combs2.addLinear(linearComb.pc17CombOfGAL, SatelliteSystem::Galileo);
            combs2.addLinear(linearComb.pc18CombOfGAL, SatelliteSystem::Galileo);
            combs2.addLinear(linearComb.pc16CombOfGAL, SatelliteSystem::Galileo);

            combs2.addLinear(linearComb.lc15CombOfGAL, SatelliteSystem::Galileo);
            combs2.addLinear(linearComb.lc17CombOfGAL, SatelliteSystem::Galileo);
            combs2.addLinear(linearComb.lc18CombOfGAL, SatelliteSystem::Galileo);
            combs2.addLinear(linearComb.lc16CombOfGAL, SatelliteSystem::Galileo);

            // BDS
            combs2.addLinear(linearComb.pc27CombOfBDS, SatelliteSystem::BDS);
            combs2.addLinear(linearComb.pc26CombOfBDS, SatelliteSystem::BDS);

            combs2.addLinear(linearComb.lc27CombOfBDS, SatelliteSystem::BDS);
            combs2.addLinear(linearComb.lc26CombOfBDS, SatelliteSystem::BDS);

        };

        // Return a string identifying this object.
        virtual std::string getClassName () const;


        // Default deconstructr
        virtual ~CommonModels() {};


    private:

        int csMethod;
        bool correctIFCB;

        LinearCombinations linearComb;

        SimpleFilter simFilter;
        MGEXDCBCorrection dcbCorr;
        RequireObservables requireObs;
        ConvertObservables convertObs;
        IFCBCorrection ifcbCorr;

          // Linear combinations
        ComputeLinear combs1;
        ComputeLinear combs2;

          // BasicModel
        BasicModel basicModel;

        ComputeTropModel computeTM;
        GravitationalDelay gravDelay;
        ComputeSatAttitude satAttitude;
        EclipsedSatFilter eclipsedSV;
        ComputeSatPCenter satPCenter;
        ComputeStaTides staTides;
        CorrectObservables correctObs;

          // MWCSDetector
        MWCSDetector markCSMW12GPS;
        MWCSDetector markCSMW15GPS;
        MWCSDetector markCSMW25GPS;
        LICSDetector markCSLI12GPS;
        LICSDetector markCSLI15GPS;

        MWCSDetector markCSMW15GAL;
        LICSDetector markCSLI15GAL;
        LICSDetector markCSLI17GAL;
        LICSDetector markCSLI18GAL;
        LICSDetector markCSLI16GAL;

        MWCSDetector markCSMW27BDS;
        LICSDetector markCSLI27BDS;
        LICSDetector markCSLI26BDS;

        ComputeLinear prefitIFCS;

        CSDetectorLC* pLCDetector;

        SatArcMarker markArc;
        ComputeWindUp windUp;

        PhaseCodeAlignment phaseAlignGPSL1;
        PhaseCodeAlignment phaseAlignGPSL2;
        PhaseCodeAlignment phaseAlignGPSL5;

        ComputeElevWeights elevWeights;
        XYZ2NEU xyz2neu;

    }; // End of class 'CommonModels'

    // @}

}; // end of namespace gpstk

#endif   // CommonModels_HPP
